﻿namespace com.stifel.ProjectMgmt
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Drawing;
    using System.Web.UI;
    using System.Web.UI.WebControls.WebParts;

    using com.stifel.Extensions.DateTimeExtensions;
    using com.stifel.Extensions.StringExtensions;
    using com.stifel.ProjectMgmtDao;

    [ToolboxItemAttribute( false )]
    public class ProjectGantt : WebPart
    {
        #region Fields

        const string ALIGNLEFT = "left";
        const string ALIGNRIGHT = "right";
        const string BACKGROUNDPOSITION = "background-position";
        const string BACKGROUNDPOSITIONTOP = "top";
        const string BACKGROUNDREPEAT = "background-repeat";
        const string BACKGROUNDREPEATX = "repeat-x";
        const string BORDERCOLLAPSE = "collapse";
        const string BORDERCOLOR = "#d8d8d8";
        const int HEIGHT = 15;
        const string MMMDYY = "MMM d, yyyy";
        const string NA = "n/a";
        const string ONMOUSEOUT = "onmouseout";
        const string ONMOUSEOVER = "onmouseover";
        const string OVERFLOWXSCROLL = "scroll";
        const string VALIGNMIDDLE = "middle";
        const string VALIGNTOP = "top";
        const int WIDTH = 15;
        const string YYMMDD = "yyyy/MM/dd";
        const string YYYYMMM = "yyyy-MMM";

        List<internalProject> _internalProjects;
        DateTime? _quarterEndDate;
        DateTime? _quarterStartDate;

        #endregion Fields

        #region Constructors

        public ProjectGantt( )
        {
        }

        #endregion Constructors

        #region Properties

        public new Font Font
        {
            get;set;
        }

        public List<StifelProject> Projects
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value that indicates the quarter (1,2,3,4)
        /// </summary>
        [Bindable( true ),
        Category( "Appearance" ),
        DefaultValue( 1 ),
        Description( "Quarter to display, valid values 1-4." )]
        public int Quarter
        {
            get;
            set;
        }

        [Bindable( true ),
        Category( "Appearance" ),
        DefaultValue( false ),
        Description( "Indicates whether the projects are displayed by due date. If false, the projects are displayed by team." )]
        public bool ShowByDueDate
        {
            get;
            set;
        }

        [Bindable( true ),
        Category( "Appearance" ),
        DefaultValue( false ),
        Description( "Indicates whether the projects are filtered to show only the projects that are impacted within the specified period. If false, all projects are displayed." )]
        public bool ShowOnlyImpactedProjects
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value that indicates the Year e.g. 2005
        /// </summary>
        [Bindable( true ),
        Category( "Appearance" ),
        DefaultValue( 2000 ),
        Description( "Year to display." )]
        public int Year
        {
            get;
            set;
        }

        string backArrowImage
        {
            get
            {
                return "~/_layouts/com.stifel.ProjectMgmt/images/back_bw.PNG";
            }
        }

        string backgroundImage
        {
            get
            {
                return "~/_layouts/com.stifel.ProjectMgmt/images/gradient64x642.png";
            }
        }

        string forwardArrowImage
        {
            get
            {
                return "~/_layouts/com.stifel.ProjectMgmt/images/forward_bw.PNG";
            }
        }

        List<internalProject> internalProjects
        {
            get
            {
                if ( _internalProjects == null )
                    _internalProjects = new List<internalProject>( );
                return _internalProjects;
            }
            set
            {
                _internalProjects = value;
            }
        }

        List<StifelProject> projects
        {
            get;
            set;
        }

        DateTime quarterEndDate
        {
            get
            {
                if ( !_quarterEndDate.HasValue )
                {
                    DateTime d = new DateTime( Year, 1, 1 );
                    _quarterEndDate = d.GetQuarterEndDate( Quarter );
                }
                return _quarterEndDate.Value;
            }
        }

        DateTime quarterStartDate
        {
            get
            {
                if ( !_quarterStartDate.HasValue )
                {
                    DateTime d = new DateTime( Year, 1, 1 );
                    _quarterStartDate = d.GetQuarterStartDate( Quarter );
                }
                return _quarterStartDate.Value;
            }
        }

        string transparentImage
        {
            get
            {
                return "~/_layouts/com.stifel.ProjectMgmt/images/20x20transparent.PNG";
            }
        }

        #endregion Properties

        #region Methods

        protected override void CreateChildControls( )
        {
        }

        protected override void OnPreRender( EventArgs e )
        {
            base.OnPreRender( e );
            if ( !base.Page.ClientScript.IsClientScriptBlockRegistered( typeof( ProjectGantt ).Name ) )
                base.Page.ClientScript.RegisterStartupScript( typeof( ProjectGantt ), typeof( ProjectGantt ).Name, "<script language=\"javascript\" type=\"text/javascript\">function resizeTables(){document.getElementById('divcal').style.width = '1px';document.getElementById('divcal').style.width = document.getElementById('tblcal').clientWidth + 'px';}$(window).load(function() {resizeTables();});$(window).resize(function() {resizeTables();});</script>" );

            initializeInternalStructures( );
        }

        protected void Page_Load( object sender, EventArgs e )
        {
        }

        protected override void Render( HtmlTextWriter writer )
        {
            base.Render( writer );

            if ( internalProjects.Count <= 0 )
            {
                writer.RenderBeginTag( HtmlTextWriterTag.H4 );
                {
                    writer.Write( "No active projects within the selected quarter." );
                    writer.RenderEndTag( );
                }
            }
            else
            {
                // create a 2 column, 1 row table, the first column will contain the text for the tasks that is non scrollable.

                writer.RenderBeginTag( HtmlTextWriterTag.Div );
                {
                    writer.AddAttribute( HtmlTextWriterAttribute.Border, "0" );
                    writer.AddAttribute( HtmlTextWriterAttribute.Cellspacing, "0" );
                    writer.AddAttribute( HtmlTextWriterAttribute.Cellpadding, "0" );
                    writer.AddAttribute( HtmlTextWriterAttribute.Width, "100%" );
                    writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.White );
                    writer.RenderBeginTag( HtmlTextWriterTag.Table );
                    {
                        writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                        {
                            writer.AddAttribute( HtmlTextWriterAttribute.Valign, VALIGNTOP );
                            writer.AddAttribute( HtmlTextWriterAttribute.Align, ALIGNRIGHT );
                            writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.White );
                            writer.RenderBeginTag( HtmlTextWriterTag.Td );
                            {
                                renderLeftPanel( writer );
                                writer.RenderEndTag( );
                            }

                            writer.AddAttribute( HtmlTextWriterAttribute.Id, "tblcal" );
                            writer.AddAttribute( HtmlTextWriterAttribute.Valign, VALIGNTOP );
                            writer.AddAttribute( HtmlTextWriterAttribute.Align, ALIGNLEFT );
                            writer.AddAttribute( HtmlTextWriterAttribute.Width, "100%" );
                            writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.White );
                            writer.RenderBeginTag( HtmlTextWriterTag.Td );
                            {
                                renderRightPanel( writer );
                                writer.RenderEndTag( );
                            }
                            writer.RenderEndTag( );
                        }

                        writer.RenderEndTag( ); // table
                    }

                    writer.RenderEndTag( ); // div
                }
            }
        }

        void filterProjects( )
        {
            projects = new List<StifelProject>( );
            if ( ShowOnlyImpactedProjects )
            {
                foreach ( StifelProject p in Projects )
                    if ( isWithinPeriod( p.StartDate, p.DueDate, quarterStartDate, quarterEndDate ) )
                        projects.Add( p );
            }
            else
                Projects.ForEach( a => projects.Add( a ) );

            sortProjects( );
        }

        ColorScheme getColor( int j )
        {
            if ( j >= ColorSchemes.BaseColors.Count - 1 )
                j = 1;
            return ColorSchemes.BaseColors[ j ];
        }

        string getImage( string alt )
        {
            return string.Format( "<span style='color:Transparent;'>A</span><img src='{0}' border='0' width='1px' height='{2}px' alt='{3}' />", transparentImage, WIDTH, HEIGHT, alt );
        }

        string getImage( )
        {
            return string.Format( "<span style='color:Transparent;'>A</span><img src='{0}' border='0' width='{1}px' height='{2}px' />", transparentImage, WIDTH, HEIGHT );
        }

        void initializeInternalStructures( )
        {
            filterProjects( );

            int i = 0;
            string currentSiteUrl = string.Empty;
            foreach ( StifelProject p in projects )
            {
                if ( string.IsNullOrEmpty( currentSiteUrl ) || !p.ParentSite.SiteUrl.Equals( currentSiteUrl ) )
                {
                    currentSiteUrl = p.ParentSite.SiteUrl;
                    i++;
                }

                internalProject internalproject = new internalProject
                {
                    ProjectDescription = p.ProjectDescription.StripHTML( ).TrimNewLine( ),
                    DueDate = p.DueDate,
                    Group = ShowByDueDate ? p.DueDate.Value.ToString( YYYYMMM ) : p.GetTeamNameAsString( ),
                    GroupColor = ShowByDueDate ? getColor( 0 ) : getColor( i ),
                    TeamName = p.GetTeamNameAsString( ),
                    ProjectColor = getColor( i ),
                    Title = p.Title,
                    StartDate = p.StartDate
                };
                internalProjects.Add( internalproject );
            }

            if ( ShowByDueDate )
                internalProjects.Sort( ( a, b ) =>
                {
                    string c = string.Format( "{0}\t{1}", a.DueDate.Value.ToString( YYMMDD ), a.Title );
                    string d = string.Format( "{0}\t{1}", b.DueDate.Value.ToString( YYMMDD ), b.Title );
                    return c.CompareTo( d );
                } );
        }

        bool isWithinPeriod( DateTime? startDate, DateTime? dueDate, DateTime quarterStartDate, DateTime quarterEndDate )
        {
            if ( startDate.HasValue && startDate.Value >= quarterStartDate && startDate.Value <= quarterEndDate )
                return true;
            else if ( dueDate.HasValue && dueDate.Value >= quarterStartDate && dueDate.Value <= quarterEndDate )
                return true;
            else if ( startDate.HasValue && dueDate.HasValue && startDate.Value < quarterStartDate && dueDate.Value > quarterEndDate )
                return true;
            return false;
        }

        string panelScrolling( )
        {
            return string.Format( "<img alt='Scroll left' src='{0}' width='12px' height='12px;' onclick=\"var o = document.getElementById('divcal');o.scrollLeft -= 45;\" /><img alt='Scroll right' src='{1}' width='12px' height='12px;' onclick=\"var o = document.getElementById('divcal');o.scrollLeft += 45;\" />", backArrowImage, forwardArrowImage );
        }

        private void renderLeftPanel( HtmlTextWriter writer )
        {
            writer.AddAttribute( HtmlTextWriterAttribute.Border, "1" );
            writer.AddStyleAttribute( HtmlTextWriterStyle.FontSize, Font.Size.ToString( ) );
            writer.AddStyleAttribute( HtmlTextWriterStyle.FontFamily, Font.Name );
            writer.AddStyleAttribute( HtmlTextWriterStyle.BorderCollapse, BORDERCOLLAPSE );
            writer.AddAttribute( HtmlTextWriterAttribute.Bordercolor, ColorSchemes.White );
            writer.AddAttribute( HtmlTextWriterAttribute.Cellspacing, "0" );
            writer.AddAttribute( HtmlTextWriterAttribute.Cellpadding, "0" );
            writer.RenderBeginTag( HtmlTextWriterTag.Table );
            {
                // write the rows
                string currentGroupName = string.Empty;
                foreach ( internalProject p in internalProjects )
                {
                    if ( string.IsNullOrEmpty( currentGroupName ) || !currentGroupName.Equals( p.Group ) )
                    {
                        currentGroupName = p.Group;
                        writeLeftMonthHeader( writer );
                        writeLeftDayHeader( writer );
                        writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                        {
                            writer.AddAttribute( HtmlTextWriterAttribute.Bgcolor, p.GroupColor.BackColor );
                            writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                            writer.AddAttribute( HtmlTextWriterAttribute.Valign, VALIGNMIDDLE );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundImage, backgroundImage );
                            writer.AddStyleAttribute( BACKGROUNDPOSITION, BACKGROUNDPOSITIONTOP );
                            writer.AddStyleAttribute( BACKGROUNDREPEAT, BACKGROUNDREPEATX );
                            writer.AddStyleAttribute( HtmlTextWriterStyle.Color, p.GroupColor.ForeColor );
                            writer.RenderBeginTag( HtmlTextWriterTag.Td );
                            {
                                writer.Write( getImage( ) );
                                writer.Write( panelScrolling( ) );
                                writer.Write( string.Format( "&nbsp;<b>{0}</b>&nbsp;", currentGroupName ) );

                                writer.RenderEndTag( );
                            }
                            writer.RenderEndTag( );
                        }
                    }

                    {
                        writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                        {
                            int j = 2;
                            if ( ShowByDueDate )
                            {
                                j--;
                                writer.AddAttribute( HtmlTextWriterAttribute.Align, ALIGNLEFT );
                                writer.AddAttribute( HtmlTextWriterAttribute.Bgcolor, p.ProjectColor.BackColor );
                                writer.AddAttribute( HtmlTextWriterAttribute.Colspan, j.ToString( ) );
                                writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                                writer.AddAttribute( HtmlTextWriterAttribute.Valign, VALIGNMIDDLE );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundImage, backgroundImage );
                                writer.AddStyleAttribute( BACKGROUNDPOSITION, BACKGROUNDPOSITIONTOP );
                                writer.AddStyleAttribute( BACKGROUNDREPEAT, BACKGROUNDREPEATX );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.Color, p.ProjectColor.ForeColor );
                                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                                {
                                    writer.Write( string.Format( "&nbsp;&nbsp;<b>{0}</>&nbsp;&nbsp;", p.TeamName ) );
                                    writer.RenderEndTag( );
                                }
                            }
                            //write the activity
                            writer.AddAttribute( HtmlTextWriterAttribute.Colspan, j.ToString( ) );
                            writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                            writer.AddAttribute( HtmlTextWriterAttribute.Valign, VALIGNMIDDLE );
                            writer.AddAttribute( ONMOUSEOVER, tooltipShow( p ) );
                            writer.AddAttribute( ONMOUSEOUT, tooltipHide( ) );
                            writer.RenderBeginTag( HtmlTextWriterTag.Td );
                            {
                                writer.Write( string.Format( "{1}{0}&nbsp;&nbsp;", p.Title, getImage( ) ) );
                                writer.RenderEndTag( );
                            }

                            writer.RenderEndTag( );
                        }
                    }
                }
                writer.RenderEndTag( );
            }
        }

        private void renderRightPanel( HtmlTextWriter writer )
        {
            List<bool> cndx = new List<bool>( );
            DateTime? startdate;
            DateTime? enddate;
            string span = string.Empty;
            int startindex, endindex, imagewidth;
            QuarterHelper quarter = new QuarterHelper( Year, Quarter );

            writer.AddAttribute( HtmlTextWriterAttribute.Id, "divcal" );
            writer.AddStyleAttribute( HtmlTextWriterStyle.Width, "1px" );
            writer.AddStyleAttribute( HtmlTextWriterStyle.OverflowX, OVERFLOWXSCROLL );
            writer.RenderBeginTag( HtmlTextWriterTag.Div );
            {
                writer.AddAttribute( HtmlTextWriterAttribute.Border, "1" );
                writer.AddAttribute( HtmlTextWriterAttribute.Bordercolor, ColorSchemes.ShadeColor );
                writer.AddAttribute( HtmlTextWriterAttribute.Cellspacing, "0" );
                writer.AddAttribute( HtmlTextWriterAttribute.Cellpadding, "0" );
                writer.AddStyleAttribute( HtmlTextWriterStyle.FontSize, Font.Size.ToString( ) );
                writer.AddStyleAttribute( HtmlTextWriterStyle.FontFamily, Font.Name );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderCollapse, BORDERCOLLAPSE );
                writer.RenderBeginTag( HtmlTextWriterTag.Table );
                {
                    // write the rows
                    string currentProject = string.Empty;
                    foreach ( internalProject p in internalProjects )
                    {
                        if ( string.IsNullOrEmpty( currentProject ) || !currentProject.Equals( p.Group ) )
                        {
                            currentProject = p.Group;
                            writeRightMonthHeader( writer, quarter );
                            writeRightDayHeader( writer, quarter, cndx );
                            // empty row to match group name
                            writeEmptyRowToRightHandColumn( writer, quarter );
                        }

                        writer.RenderBeginTag( HtmlTextWriterTag.Tr );
                        {
                            if ( isWithinPeriod( p.StartDate, p.DueDate, quarterStartDate, quarterEndDate ) )
                            {
                                if ( p.StartDate.HasValue )
                                    startdate = p.StartDate;
                                else
                                    startdate = p.DueDate;
                                enddate = p.DueDate;

                                startindex = quarter.getColumnIndex( startdate );
                                endindex = quarter.getColumnIndex( enddate );

                                //write out the padding cells
                                writeLeftPadding( writer, startindex, cndx );

                                //create the filled in block
                                writer.AddAttribute( HtmlTextWriterAttribute.Colspan, ( endindex - startindex + 1 ).ToString( ) );
                                writer.AddAttribute( HtmlTextWriterAttribute.Nowrap, true.ToString( ) );
                                writer.AddAttribute( ONMOUSEOVER, tooltipShow( p ) );
                                writer.AddAttribute( ONMOUSEOUT, tooltipHide( ) );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundImage, backgroundImage );
                                writer.AddStyleAttribute( BACKGROUNDPOSITION, BACKGROUNDPOSITIONTOP );
                                writer.AddStyleAttribute( BACKGROUNDREPEAT, BACKGROUNDREPEATX );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.BackgroundColor, p.ProjectColor.BackColor );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.Color, p.ProjectColor.BackColor );
                                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                                {
                                    imagewidth = ( endindex - startindex + 1 ) * WIDTH;
                                    writer.Write( getImage( p.Title ) );
                                    writer.RenderEndTag( );
                                }

                                //write out the padding cells
                                writeRightPadding( writer, endindex, quarter.Days - 1, cndx );
                            }
                            else
                            {
                                writeLeftPadding( writer, quarter.Days, cndx );
                            }
                            writer.RenderEndTag( );
                        }
                    }
                    for ( int i = 0; i < quarter.Days; i++ )
                    {
                        writer.AddStyleAttribute( HtmlTextWriterStyle.Color, ColorSchemes.White );
                        writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.White );
                        writer.RenderBeginTag( HtmlTextWriterTag.Td );
                        {
                            writer.Write( getImage( ) );
                            writer.RenderEndTag( );
                        }
                    };

                    writer.RenderEndTag( ); // table
                }
                writer.RenderEndTag( ); // div
            }
        }

        void sortProjects( )
        {
            projects.Sort( ( a, b ) =>
            {
                string c = string.Format( "{0}\t{1}", a.GetTeamNameAsString( ), a.Title );
                string d = string.Format( "{0}\t{1}", b.GetTeamNameAsString( ), b.Title );
                return c.CompareTo( d );
            } );
        }

        string tooltipHide( )
        {
            return "tooltip.hide();";
        }

        string tooltipShow( internalProject p )
        {
            return string.Format( "tooltip.show('{0}');", p.ToolTip );
        }

        void writeEmptyRowToRightHandColumn( HtmlTextWriter writer, QuarterHelper quarter )
        {
            writer.RenderBeginTag( HtmlTextWriterTag.Tr );
            {
                writer.AddAttribute( HtmlTextWriterAttribute.Colspan, ( quarter.Days ).ToString( ) );
                writer.AddAttribute( HtmlTextWriterAttribute.Width, ( ( quarter.Days ) * WIDTH ).ToString( ) );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                {
                    writer.Write( string.Format( "&nbsp;&nbsp;{0}", getImage( ) ) );
                    writer.RenderEndTag( );
                }
                writer.RenderEndTag( );
            }
        }

        void writeLeftDayHeader( HtmlTextWriter writer )
        {
            writer.RenderBeginTag( HtmlTextWriterTag.Tr );
            {
                writer.AddAttribute( HtmlTextWriterAttribute.Colspan, "3" );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.White );
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                {
                    writer.Write( "&nbsp;<br/>&nbsp;" );
                    writer.RenderEndTag( );
                }
                writer.RenderEndTag( );
            }
        }

        void writeLeftMonthHeader( HtmlTextWriter writer )
        {
            //empty row to match month headers on right hand pane
            writer.RenderBeginTag( HtmlTextWriterTag.Tr );
            {
                writer.AddAttribute( HtmlTextWriterAttribute.Colspan, "3" );
                writer.AddAttribute( HtmlTextWriterAttribute.Align, ALIGNLEFT );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, ColorSchemes.White );
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                {
                    writer.Write( "&nbsp;" );
                    writer.RenderEndTag( );
                }
                writer.RenderEndTag( );
            }
        }

        void writeLeftPadding( HtmlTextWriter writer, int startindex, List<bool> cndx )
        {
            for ( int i = 0; i < startindex; i++ )
            {
                string color = ColorSchemes.White;
                if ( cndx[ i ] )
                {
                    color = ColorSchemes.ShadeColor;
                    writer.AddAttribute( HtmlTextWriterAttribute.Bgcolor, ColorSchemes.ShadeColor );
                }

                writer.AddStyleAttribute( HtmlTextWriterStyle.Color, color );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                {
                    // writer.Write( string.Format( "<img src='{0}' border='0' width='{1}' height='{2}' />", transparentImage, WIDTH, HEIGHT ) );
                    writer.Write( getImage( ) );
                    writer.RenderEndTag( );
                }
            };
        }

        void writeRightDayHeader( HtmlTextWriter writer, QuarterHelper quarter, List<bool> cndx )
        {
            writer.RenderBeginTag( HtmlTextWriterTag.Tr );
            for ( int i = ( 3 * quarter.Index - 2 ); i <= ( 3 * quarter.Index ); i++ )
            {
                for ( int j = 1; j <= quarter.TotalDaysInMonth( i ); j++ )
                {
                    DateTime d = new DateTime( Year, i, j );
                    string dayname = d.DayOfWeek.ToString( ).Substring( 0, 1 );
                    bool week = d.IsWeekend( );
                    cndx.Add( week );

                    writer.AddAttribute( HtmlTextWriterAttribute.Align, "center" );
                    if ( week )
                        writer.AddAttribute( HtmlTextWriterAttribute.Bgcolor, ColorSchemes.ShadeColor );
                    writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                    writer.RenderBeginTag( HtmlTextWriterTag.Td );
                    writer.Write( string.Format( "{0}<br/>{1}", dayname, j ) );
                    writer.RenderEndTag( );
                }
            }
            writer.RenderEndTag( );
        }

        void writeRightMonthHeader( HtmlTextWriter writer, QuarterHelper quarter )
        {
            writer.RenderBeginTag( HtmlTextWriterTag.Tr );
            for ( int i = 1; i <= 3; i++ )
            {
                int month = i + ( 3 * ( quarter.Index - 1 ) );
                writer.AddAttribute( HtmlTextWriterAttribute.Align, "center" );
                writer.AddAttribute( HtmlTextWriterAttribute.Colspan, quarter.TotalDaysInMonth( month ).ToString( ) );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                writer.Write( string.Format( "<b>{0}</b>", quarter.GetMonthName( i ) ) );
                writer.RenderEndTag( );
            };
            writer.RenderEndTag( );
        }

        void writeRightPadding( HtmlTextWriter writer, int endindex, int days, List<bool> cndx )
        {
            for ( int i = endindex; i < days; i++ )
            {
                string color = ColorSchemes.White;
                if ( cndx[ i + 1 ] )
                {
                    color = ColorSchemes.ShadeColor;
                    writer.AddAttribute( HtmlTextWriterAttribute.Bgcolor, ColorSchemes.ShadeColor );
                }

                writer.AddStyleAttribute( HtmlTextWriterStyle.Color, color );
                writer.AddStyleAttribute( HtmlTextWriterStyle.BorderColor, BORDERCOLOR );
                writer.RenderBeginTag( HtmlTextWriterTag.Td );
                {
                    writer.Write( getImage( ) );
                    writer.RenderEndTag( );
                }
            };
        }

        #endregion Methods

        #region Nested Types

        private class QuarterHelper
        {
            #region Constructors

            public QuarterHelper( )
            {
            }

            public QuarterHelper( int year, int quarter )
            {
                Index = quarter;
                Year = year;
                Names = getQuarterNames( quarter );
                Days = getDaysInQuarter( Year, Index );
            }

            #endregion Constructors

            #region Properties

            public int Days
            {
                get;
                private set;
            }

            public int Index
            {
                get;
                private set;
            }

            public string[] Names
            {
                get;
                private set;
            }

            public int Year
            {
                get;
                set;
            }

            #endregion Properties

            #region Methods

            public int getColumnIndex( DateTime? date )
            {
                DateTime d = date.Value;
                int offset = 0;
                int r = 0;
                for ( int i = 1; i < Index; i++ )
                    offset += d.GetDaysInQuarter( i );
                r = ( d.DayOfYear - 1 ) - offset;
                if ( r < 0 )
                    r = 0;
                if ( r > d.GetDaysInQuarter( Index ) )
                    r = d.GetDaysInQuarter( Index );
                return r;
            }

            public string GetMonthName( int i )
            {
                return Names[ i - 1 ];
            }

            public bool IsWeekend( int month, int day )
            {
                DateTime d = new DateTime( Year, month, day );
                return ( d.DayOfWeek == DayOfWeek.Saturday || d.DayOfWeek == DayOfWeek.Sunday ) ? true : false;
            }

            public int TotalDaysInMonth( int i )
            {
                return DateTime.DaysInMonth( Year, i );
            }

            private int getDaysInQuarter( int year, int quarter )
            {
                DateTime startDate;
                DateTime endDate;
                if ( quarter < 4 )
                {
                    startDate = new DateTime( year, ( 3 * quarter - 2 ), 1 );
                    endDate = new DateTime( year, ( 3 * quarter - 2 ) + 3, 1 );
                }
                else
                {
                    startDate = new DateTime( year, ( 3 * quarter - 2 ), 1 );
                    endDate = new DateTime( year + 1, 1, 1 );
                }

                TimeSpan t = new TimeSpan( endDate.Subtract( startDate ).Ticks );
                return t.Days;
            }

            private string[] getQuarterNames( int quarter )
            {
                int q = quarter < 1 ? 1 : quarter > 4 ? 4 : quarter;
                List<string> l = new List<string>( );
                for ( int i = quarter * 3 - 2; i <= quarter * 3; i++ )
                {
                    l.Add( new DateTime( 2000, i, 1 ).ToString( "MMMM" ) );
                }
                return l.ToArray( );
            }

            #endregion Methods
        }

        #endregion Nested Types
    }
}